package own.stu.inter.crawler;

import com.google.common.io.CharSink;
import com.google.common.io.CharSource;
import com.google.common.io.FileWriteMode;
import com.google.common.io.Files;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Data
public class FileMergeService implements Callable {

    Map<Integer, List<String>> mergeListMap = new HashMap<>();
    Map<String, Boolean> pathLoadedMap = new ConcurrentHashMap<>();
    AtomicInteger pageIdx = new AtomicInteger(0);
    AtomicInteger starPageIdx = new AtomicInteger(0);

    public void addPageList(List<String> mergeInfos) {
        int pathIdx = pageIdx.getAndIncrement();
        mergeListMap.put(pathIdx, mergeInfos);
        for (String info : mergeInfos) {
            pathLoadedMap.put(info, false);
        }
    }

    public void markLoaded(String path) {
        pathLoadedMap.put(path, true);
    }

    static String rootPath = "/Users/qim/Desktop/novel/";

    private String fileName;
    private Crawler crawler;

    public FileMergeService(String fileName, Crawler crawler) {
        this.fileName = fileName;
        this.crawler = crawler;
    }

    @Override
    public Object call() throws Exception {

        File file = new File(rootPath + fileName);
        if (!file.exists()) {
            Files.touch(file);
        }
        CharSink charSink = Files.asCharSink(file, Charset.defaultCharset(), FileWriteMode.APPEND);

        while (true) {
            log.info("start merge");
            if (crawler.isPageDirListLoadDone() && crawler.getTasks().get() <= 0) {
                log.info("merge done ");
                break;
            }
            int curPage = starPageIdx.getAndIncrement();
            List<String> paths = mergeListMap.get(curPage);
            if (CollectionUtils.isEmpty(paths)) {
                sleep(200);
            }

            log.info("merge pageIdx : {}", curPage);
            for (String path : paths) {
                final Boolean loaded = pathLoadedMap.get(path);
                do {
                    if (!loaded) {
                        sleep(500);
                    } else {
                        break;
                    }
                } while (true);

                log.info("merge pageIdx : {} , path : {}", curPage, path);
                // loadfile and merge
                CharSource charSource = Files.asCharSource(new File(rootPath + path), Charset.defaultCharset());
                charSource.forEachLine(v -> {
                    try {
                        charSink.write("\n");
                        charSink.write(v);
                    } catch (IOException e) {
                        log.error(" ---- ", e);
                    }
                });
                crawler.getTasks().decrementAndGet();
            }
        }
        return "done";
    }

    private void sleep(long sleepTime) {
        try {
            TimeUnit.MILLISECONDS.sleep(sleepTime);
        } catch (InterruptedException e) {
            log.error(" ---- ", e);
        }
    }


    public static void main(String[] args) throws IOException {

        File fileDir = new File(rootPath);
        if (!fileDir.isDirectory()) {
            return;
        }
        File[] files = fileDir.listFiles();
        Arrays.sort(files, Comparator.comparing(File::getName));

        final File file = new File(rootPath + "new_1.txt");
        if (!file.exists()) {
            Files.touch(file);
        }
        // get given file
        // merge
        CharSink charSink = Files.asCharSink(file, Charset.defaultCharset(), FileWriteMode.APPEND);

        for (File f : files) {
            if(f.getName().indexOf(".") >= 0){
                continue;
            }

            CharSource charSource = Files.asCharSource(f, Charset.defaultCharset());
            charSink.writeFrom(charSource.openStream());
            /*charSource.forEachLine(v -> {
                try {
                    charSink.write(v);
                } catch (IOException e) {
                    log.error(" ---- ", e);
                }
            });
            charSink.write("\n");*/
        }
    }
}
